#include "d3d.h"
#include "d3d_mesh.h"
#include "interface_types.h"
#include ".\shaders\d3d_shader.h"
#include ".\shaders\d3d_watershader.h"
#include ".\shaders\d3d_lightshader.h"
#include "d3d_texture.h"
#include "d3d_util.h"
#include "../engine/engine.h"
#include "../engine/error.h"
#include "../math/math.h"
#include "../common/def.h"
#include "../common/util.h"
#include "../common/types.h"
#include "../common/string.h"
#include "../common/format.h"
#include "../common/hashtable.hpp"

/**************************************
 *Assignment operator allows this data
 *structure to be used in array lists
 **************************************/
D3DMesh::RenderInstance D3DMesh::RenderInstance::operator = (const D3DMesh::RenderInstance& v)
{
	if(this != &v)
	{
		m_pMesh		= v.m_pMesh; 
		m_Frame		= v.m_Frame; 
		memcpy(&m_Transformation, &v.m_Transformation, sizeof(D3DXMATRIX)); 
	}
	return *this; 
}
void D3DMesh::Render(const unsigned int vbOffset)
{
	GetDevice()->GetDevice()->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vbOffset, 0, 
		m_numVerts, 0,m_NumPrimitives); 
}

/**************************************
 *
 **************************************/
D3DMesh* D3DModelLOD::getMesh(unsigned int index)
{
	return (index < m_meshCount && m_pMeshs) ? m_pMeshs[index] : NULL; 
}



/**************************************
 *
 **************************************/
D3DMesh::D3DMesh(CD3D9Device* const pDevice) : D3DRenderable(pDevice)
{
	m_RenderFlags = RENDER_MODEL; 
	m_numVerts	= 0; 
	m_NumPrimitives	= 0; 
	m_numFrames	= 0; 
	m_NumPrimitives	= 0; 
	m_vertArrayBaseIdx	= 0; 
	
	m_pVertices	= NULL; 
	m_pTextureUnitA	= NULL; 
	m_pTextureUnitB	= NULL; 
	m_pTextureUnitC	= NULL;
	m_pTextureMask	= NULL;
	m_pTextureGI	= NULL;

	m_pIndicies	= NULL; 
	m_pShader	= NULL; 
	
	m_Identity	= 0; 


	m_pShader = NULL; 
	//pDevice = CEngine::GetInstance()->GetRenderer(); 
	pVertexBuffer = NULL; 
	pIndexBuffer = NULL; 
}

/**************************************
 *
 **************************************/
D3DMesh::~D3DMesh(void)
{
	Release(); 
	EE_SAFEDELETEARRAY(m_pVertices); 
	EE_SAFEDELETEARRAY(m_pIndicies); 
}

HRESULT D3DMesh::Reload()
{
	//TODO:
	return S_OK; 
}



/**************************************
 *
 **************************************/
void D3DMesh::setTexture(Texture* pTexture, const unsigned int unit)
{
	switch(unit)
	{
	case D3DShader::UNIT_A:
		{
		m_pTextureUnitA = pTexture;  break; 
		}
	case D3DShader::UNIT_B:
		{
		m_pTextureUnitB = pTexture;  break; 
		}
	case D3DShader::UNIT_C:
		{
		m_pTextureUnitC = pTexture;  break; 
		}
	case D3DShader::UNIT_MASK:
		{
		m_pTextureMask = pTexture;  break; 
		}
	}
}

/**************************************
 *
 **************************************/
D3DMesh::RenderInstance::RenderInstance() : m_pMesh(NULL), m_Frame(0.0f), m_Transformation(Matrix4f::identity())
{	}

/**************************************
 *
 **************************************/
D3DMesh::RenderInstance::RenderInstance(D3DMesh *pMesh, const Matrix4f& transformation, float frame) : m_pMesh(pMesh), 
m_Frame(frame), m_Transformation(transformation)
{	}

string D3DMesh::GetType() const
{
	return string("D3DMesh"); 
}


/**************************************
 *Releases all data associated with this
 *mesh
 **************************************/
HRESULT	D3DMesh::Release(void)
{
	m_IsValid = false; 
	HRESULT returnStatus = S_OK; 
	try{

		//Release any device data
		if(pVertexBuffer)
		{
			returnStatus = (pVertexBuffer->Release() != D3D_OK) ? E_FAIL : S_OK; 
			pVertexBuffer = NULL; 
		}

		if(pIndexBuffer)
		{
			returnStatus = (pIndexBuffer->Release() != D3D_OK) ? E_FAIL : S_OK; 
			pIndexBuffer = NULL; 
		}

		//Clears this mesh from it's shaders buffers
		m_pShader->PostExecute();
		if(m_RenderFlags & RENDER_LIGHTING)
		{
			GetDevice()->m_pLightShader->PostExecute();
		}
		m_pTextureUnitA	= NULL; 
		m_pTextureUnitB	= NULL; 
		m_pTextureUnitC = NULL;
		m_pTextureMask	= NULL; 

		EE_SAFEDELETEARRAY(m_pIndicies); 
		EE_SAFEDELETEARRAY(m_pVertices); 

		m_Identity = 0; 

		if(FAILED(returnStatus))
			throw EE_EXCEPTION("Failed to Release D3DMesh resources"); 

		return S_OK; 
	}
	catch(CError::CErrorData errorData)
	{
		CError::CError(errorData); 
		return E_FAIL; 
	}
}
HRESULT D3DMesh::Create(const MeshPartData& data)
{
	void *pTmpVertices = NULL; 
	void *pTmpIndicies = NULL; 
	unsigned int vbSize = 0; 
	unsigned int ibSize = 0; 

	try {
		if(data.frameCount * data.vertexCount * data.triangleCount <= 0)
			throw EE_EXCEPTION("Invalid mesh data."); 

		vbSize = (data.frameCount * data.vertexCount) * VertexComplex::size; 
		ibSize = (data.frameCount * data.triangleCount * 3) * sizeof(unsigned short); 
		if(vbSize <= 0 || ibSize <= 0)
			throw EE_EXCEPTION("Invalid vertex/index buffer size."); 


		m_numFrames = data.frameCount; 
		m_NumPrimitives = data.triangleCount; 
		m_numVerts = data.vertexCount; 
		m_pIndicies = data.m_pIndicies; 
		m_pVertices = data.m_pVertices; 

		GetVertexCloudMetrics(m_pVertices, m_numVerts, NULL, &m_Radius);

		//Load textures if they are required
		if(data.diffuseMap.IsValid())
		{
			if(FAILED(GetDevice()->CreateTexture(data.diffuseMap,&m_pTextureUnitA)))
				m_pTextureUnitA = GetDevice()->GetErrorTexture(); 
		}else {
			m_pTextureUnitA = GetDevice()->GetErrorTexture(); 
		}

		if(data.bumpMap.IsValid()) {
			if(FAILED(GetDevice()->CreateTexture(data.bumpMap,&m_pTextureUnitB)))
				m_pTextureUnitB = GetDevice()->GetErrorTexture(); 
		} else {
			m_pTextureUnitB = GetDevice()->GetDefaultNMTexture(); 
		}

		if(data.specularMap.IsValid()) {
			if(FAILED(GetDevice()->CreateTexture(data.specularMap,&m_pTextureUnitC)))
				m_pTextureUnitC = GetDevice()->GetErrorTexture(); 
		}
		else {
			m_pTextureUnitC = GetDevice()->GetWhiteTexture(); 
		}

		if(data.opacityMap.IsValid()) {
			if(FAILED(GetDevice()->CreateTexture(data.opacityMap,&m_pTextureMask)))
				m_pTextureMask = GetDevice()->GetErrorTexture(); 
		}
		else {
			m_pTextureMask = NULL;//GetDevice()->GetWhiteTexture(); 
		}

		if(data.giMap.IsValid()) {
			if(FAILED(GetDevice()->CreateTexture(data.giMap,&m_pTextureGI)))
				m_pTextureGI = GetDevice()->GetErrorTexture(); 
		}
		else {
			m_pTextureGI = GetDevice()->GetDefaultAOTexture(); 
		}

		//Load the shader associated with this mesh
		if(FAILED(GetDevice()->CreateShader((D3DShader**)&m_pShader, data.shaderFilename)))
			m_pShader = GetDevice()->GetDefaultShader(); 
				
		//Create a device vertex buffer
		if(GetDevice()->GetDevice()->CreateVertexBuffer(vbSize,D3DUSAGE_WRITEONLY,0,
			D3DPOOL_DEFAULT,&pVertexBuffer,NULL) != D3D_OK)
			throw EE_EXCEPTION("Failed to Create vertex buffer."); 

		//Copy the data into the vertex buffer
		if(pVertexBuffer->Lock(0, vbSize, (void **) &pTmpVertices, 0) != D3D_OK)
			throw EE_EXCEPTION("Failed to lock vertex buffer."); 
		memcpy(pTmpVertices, data.m_pVertices, vbSize); 
		if(pVertexBuffer->Unlock() != D3D_OK)
			throw EE_EXCEPTION("Failed to unlock vertex buffer."); 
		
		//Create a device index buffer
		if(GetDevice()->GetDevice()->CreateIndexBuffer(ibSize,0,D3DFMT_INDEX16,
			D3DPOOL_MANAGED,&pIndexBuffer,NULL) != D3D_OK)
			throw EE_EXCEPTION("Failed to Create index buffer."); 
		
		//Copy the data into the index buffer
		if(pIndexBuffer->Lock(0, ibSize, (void **) &pTmpIndicies, 0) != D3D_OK)
			throw EE_EXCEPTION("Failed to lock index buffer."); 
		memcpy(pTmpIndicies, data.m_pIndicies, ibSize); 
		if(pIndexBuffer->Unlock() != D3D_OK)
			throw EE_EXCEPTION("Failed to unlock index buffer."); 
	
		return S_OK;
	}
	catch(CError::CErrorData error)
	{
		CError(error, ERRORREPORT_LOG);	
		return E_FAIL;
	}
}

Texture* D3DMesh::getMaskTexture()
{
	return m_pTextureMask;
}

Texture* D3DMesh::getTexture(const unsigned int idx)
{
	switch(idx)
	{
	case 0:
		return m_pTextureUnitA;
	case 1:
		return m_pTextureUnitB;
	case 2:
		return m_pTextureUnitC;
	case 3:	
		return m_pTextureMask;
	case 4:
		return m_pTextureGI;
	}
	return NULL;
}
/**************************************
 *
 **************************************/
D3DModelLOD::D3DModelLOD(CD3D9Device* const pDevice) : IResource(pDevice)
{
	m_pMeshs	= NULL;
	m_meshCount	= 0;
}

D3DModelLOD::D3DModelLOD(CD3D9Device* const pDevice, D3DMesh** pMeshData, unsigned int meshCount) : IResource(pDevice)
{
	m_pMeshs = pMeshData;
	m_meshCount = meshCount;
}

/**************************************
 *
 **************************************/
D3DModelLOD::~D3DModelLOD()
{	
	Release();
}

string D3DModelLOD::GetType() const
{
	return string("D3DModelLOD"); 
}

/**************************************
 *Renders the current model according to
 *the passed parameters
 **************************************/
void D3DModelLOD::Draw(const Matrix4f &transform, D3DShader * const m_pShader, const float frame)
{
//	m_Radius.m_TransformedCenterOffset = (MATRIX3X3F::transpose(&MATRIX3X3F(&transform)) * m_Radius.m_CenterOffset) + transform.Translation(); 

	CD3D9Device* pRenderDevice = CEngine::GetInstance()->GetRenderer(); 	
	for(unsigned int i = 0;  i < m_meshCount;  i++)
		pRenderDevice->AddRenderQue(m_pMeshs[i], transform, m_pShader); 

}

/**************************************
 *Renders the current model according to
 *the passed parameters
 **************************************/
void D3DModelLOD::Draw(const Matrix4f &transform, const float frame)
{
//	m_Radius.m_TransformedCenterOffset = (MATRIX3X3F::transpose(&MATRIX3X3F(&transform)) * m_Radius.m_CenterOffset) + transform.Translation(); 

	CD3D9Device* pRenderDevice = CEngine::GetInstance()->GetRenderer(); 
	for(unsigned int i = 0;  i < m_meshCount;  i++)
		pRenderDevice->AddRenderQue(m_pMeshs[i], transform); 

	/*if(this->identity.equals("Ground.wld"))
	{; }*/

}

/**************************************
 *Attempts to Release and reload all 
 *resources associated with this model
 **************************************/
HRESULT	D3DModelLOD::Reload(void)
{

	return S_OK; 
}

/**************************************
 *Attempts to Release all resources
 *associated with this model
 **************************************/
HRESULT D3DModelLOD::Release()
{
	m_IsValid = false; 
	CD3D9Device* pRenderDevice = CEngine::GetInstance()->GetRenderer(); 
	pRenderDevice->DeregisterResource(this); 

	for(unsigned int i = 0;  i < m_meshCount;  i++)
	{
		if(m_pMeshs[i])
		{
			m_pMeshs[i]->Release(); 
			EE_SAFEDELETE(m_pMeshs[i]); 
		}
	}

	EE_SAFEDELETEARRAY(m_pMeshs); 
	m_meshCount = 0; 
	m_Identity.empty(); 

	return S_OK; 
}

void D3DModelLOD::setRenderFlags(const int flags)
{
	if(m_pMeshs)
	{
		for(unsigned int i = 0;  i < m_meshCount;  i++)
			m_pMeshs[i]->setRenderFlags(flags); 
	}
}

/**************************************
 *
 **************************************/
unsigned int D3DModelLOD::getMeshCount() const
{
	return m_meshCount; 
}

/**************************************
 *
 **************************************/
D3DModel::D3DModel(CD3D9Device *const pDevice) : IResource(pDevice)
{
	m_RenderFlags = RENDER_DEFAULT;
	m_pLODs		= NULL; 
	m_LODCount	= 0; 
}

/**************************************
 *
 **************************************/
D3DModel::D3DModel(CD3D9Device* const pDevice, D3DModelLOD** pLODs, unsigned int LODCount) : IResource(pDevice)
{
	m_RenderFlags = RENDER_DEFAULT;
	m_pLODs		= pLODs; 
	m_LODCount	= LODCount; 
	
	CaclulateBoundSphere();
}

/**************************************
 *
 **************************************/
D3DModel::~D3DModel()
{
	Release();
}

/**************************************
 * Retruns respective LOD via index. If
 * index is too large, NULL is returned.
 * Use getLODCount() to find number of LOD's
 * in model instance
 **************************************/
D3DModelLOD* D3DModel::getLOD(unsigned int index)
{
	return (index < m_LODCount) ? m_pLODs[index] : NULL;
}

/**************************************
 * Retruns respective LOD via index. If
 * index is too large, NULL is returned
 **************************************/
unsigned int D3DModel::getLODCount() const
{
	return m_LODCount;
}

///**************************************
// * Retruns the computed radius of the
// * overall model. Requires that
// * CaclulateBoundSphere() has already been
// * called
// **************************************/
//float D3DModel::GetRadius() const
//{
//	return m_Radius;
//}
/**************************************
 * Retruns the computed radius of the
 * overall model. Requires that
 * CaclulateBoundSphere() has already been
 * called
 **************************************/
Spheref D3DModel::GetBounds() const
{
	return m_Bounds;
}

/**************************************
 * Sets the model as either instanced or 
 * not. If only on instance will exisit
 * then set this as false
 **************************************/
void D3DModel::SetIsInstanced(bool value) {

	D3DModelLOD *pLOD;
	for(uint i = 0; i < m_LODCount; i++) {
		
		pLOD = m_pLODs[i];
		if(pLOD) {
			for(uint j = 0; j < pLOD->m_meshCount; j++)
				pLOD->m_pMeshs[j]->m_IsInstance = value;
		}			
	}
}

/**************************************
 * Sets the render flags of each LOD in
 * the model
 **************************************/
void D3DModel::setRenderFlags(const int flags)
{
	for(unsigned int i = 0; i < m_LODCount; i++)
	{
		D3DModelLOD *pLOD = m_pLODs[i];
		if(!ISNULL(pLOD))
			pLOD->setRenderFlags(flags);

		m_RenderFlags = flags;
	}
}
/**************************************
 * Reloads the models data
 **************************************/
HRESULT D3DModel::Reload()
{
	//TODO:implement
	return S_OK;
}

/**************************************
 * Releases the models data
 **************************************/
HRESULT D3DModel::Release()
{
	HRESULT result = S_OK;
	for(unsigned int i = 0; i < m_LODCount; i++)
	{
		D3DModelLOD* pLOD = m_pLODs[i];
		if(ISNULL(pLOD))
			continue;

		if(FAILED(pLOD->Release()))
		{
			result = E_FAIL;
			EE_LOGERROR("Failed to Release model LOD");
		}

		EE_SAFEDELETE(pLOD); 	
	}

	EE_SAFEDELETEARRAY(m_pLODs);
	m_LODCount = 0;
	return result;
}

/**************************************
 * 
 **************************************/
void D3DModel::CaclulateBoundSphere()
{
	HRESULT hr;
	Spheref bounds;

	do {

		D3DModelLOD* pBaseLOD =  m_pLODs[0];
		if(ISNULL(pBaseLOD)){
			hr = E_UNEXPECTED;
			EE_LOGERROR("Bad model state.");
			break;
		}

		cuint meshCount = pBaseLOD->getMeshCount();
		if(meshCount == 0){
			hr = E_UNEXPECTED;
			EE_LOGERROR("Bad model state.");
			break;
		}

		Vector3f min = Vector3f(); 
		Vector3f max = Vector3f(); 
		
		hr = E_UNEXPECTED;

		for(uint i = 0;  i < meshCount;  i++)
		{	
			D3DMesh* pMesh = pBaseLOD->m_pMeshs[i];
			cuint vertexCount = pMesh->m_numVerts;
			
			if(vertexCount > 0)
			{
				if(i == 0) {
					min = max = Vector3f(pMesh->m_pVertices[0].position);
					hr = S_OK;
				}
				
				for(uint j = 0;  j < vertexCount;  j++)
				{
					Vector3f::maxVec(&max, &max, &Vector3f(pMesh->m_pVertices[j].position)); 
					Vector3f::minVec(&min, &min, &Vector3f(pMesh->m_pVertices[j].position)); 
				}
			}
		}

		bounds.m_center = (min + max) / 2.0f; 
		bounds.m_radius = MAX(Vector3f::distance(&min,&bounds.m_center), Vector3f::distance(&max,&bounds.m_center)); 
		m_Bounds = bounds;
		return;

	}while(false);

	if(FAILED(hr)) {
		EE_LOGERROR("Failed to compute bounds sphere.");
	}
	
}

/**************************************
 * 
 **************************************/
string D3DModel::GetType() const
{
	return string("D3DModel"); 
}

/**************************************
 * Draws the model instance
 **************************************/
void D3DModel::Draw(const Matrix4f &transform, D3DShader * const m_pShader, const Vector3f& velocity)
{
	ViewOrrientation* pCamera = GetDevice()->GetViewOrrientation();

	if(!(m_RenderFlags & RENDER_NOCLIPPING))
	{
		if(!ViewOrrientation::ContainsSphere(pCamera,&Spheref(transform._M41,transform._M42,transform._M43, m_Bounds.m_radius)))
			return;
		/*if(!GetDevice()->BoundSphereInFrustum(pCamera, &Spheref(transform._M41,transform._M42,transform._M43, m_Bounds.m_radius)))
			return;*/
	}

	m_pLODs[0]->Draw(transform, m_pShader, 0.0f);
}

/**************************************
 * Draws the model instance
 **************************************/
void D3DModel::Draw(const Matrix4f &transform, const Vector3f& velocity)
{
	
	//TODO: this is pretty bad for usual cases
	if(m_RenderFlags & (RENDER_CAST_SHADOW | RENDER_NOCLIPPING))
		m_pLODs[0]->Draw(transform, 0.0f);
	else {
		
		ViewOrrientation* pCamera = GetDevice()->GetViewOrrientation();

		//if(GetDevice()->BoundSphereInFrustum(pCamera,&Spheref(m_Bounds.m_center + transform.Translation(), m_Bounds.m_radius))) 
		if(ViewOrrientation::ContainsSphere(pCamera,&Spheref(m_Bounds.m_center + transform.Translation(), m_Bounds.m_radius))) {
			m_pLODs[0]->Draw(transform, 0.0f);
		}
	}
}

/**************************************
 * Draws the model instance at the orgion
 **************************************/
void D3DModel::Draw(const Vector3f& velocity) {

	if(m_RenderFlags & (RENDER_CAST_SHADOW | RENDER_NOCLIPPING))
		m_pLODs[0]->Draw(Matrix4f::identity(), 0.0f);
	else {
		
		ViewOrrientation* pCamera = GetDevice()->GetViewOrrientation();
		
		if(ViewOrrientation::ContainsSphere(pCamera,&Spheref(m_Bounds.m_center, m_Bounds.m_radius))) {
			m_pLODs[0]->Draw(Matrix4f::identity(), 0.0f);
		}
	}

}

/**************************************
 *Reads model data from the specified file
 *name into the model data structure provided
 **************************************/
HRESULT CD3D9Device::CreateModel(const string &filename, D3DModel **pOut)
{
	D3DModel *lpModel = NULL; 
	D3DModel *lppModel = NULL; 
	FILE *pFP			= NULL; 
	D3DModelLOD *pModel		= NULL; 
	short endCheck = -1; 
	short version;
	short GImap;
	short LODCount;
	string giMap;

	try
	{
		//Look for this model in the existing models list and if found
		//return it
		if(SUCCEEDED(SearchForResource(filename, (IResource**) &lppModel, RESOURCE_MODEL)))
		{
			if(lppModel)
			{
				*pOut = lppModel; 
				return S_OK; 
			}
		}

		pFP = CEngine::GetInstance()->FindFile(filename); 
		if(ISNULL(pFP))
			throw EE_EXCEPTION("Could not open model file."); 
		
		fread(&version, sizeof(short), 1, pFP);
		if(version != EE_MODEL_ID)
			throw EE_EXCEPTION("Unknown model version."); 

		giMap = CUtil::readString(pFP);
		//fread(&GImap, sizeof(short), 1, pFP);

		fread(&LODCount, sizeof(short), 1, pFP);
		if(LODCount <= 0)
			throw EE_EXCEPTION("No data in model file."); 

		//TODO: skip through the mesh and seek for model data start??


		lpModel = new D3DModel(this);	
		lpModel->m_Identity = filename; 
		lpModel->m_LODCount = LODCount;
		lpModel->m_pLODs = new D3DModelLOD* [ LODCount ];

		//Load in model data
		for(unsigned short L = 0; L < (unsigned short)LODCount; L++)
		{
			short numLODParts = 0;
			fread(&numLODParts, sizeof(short), 1, pFP);

			if(numLODParts <= 0)
			{
				EE_LOGERROR("Model LOD contained no data");
				continue;
			}

			D3DModelLOD* pModelLOD = new D3DModelLOD(this);
			pModelLOD->m_meshCount = numLODParts;
			pModelLOD->m_pMeshs = new D3DMesh* [numLODParts];

			for(unsigned short p = 0;  p < (unsigned short)numLODParts;  p++)
			{	
				MeshPartData LODData;

				int faceCount = 0;
				fread(&faceCount, sizeof(int), 1, pFP);
				
				//Read material data 
				LODData.shaderFilename = CUtil::readString(pFP);
				
				fread(&LODData.opacity, sizeof(float), 1, pFP);

				LODData.diffuseMap = CUtil::readString(pFP);
				LODData.bumpMap = CUtil::readString(pFP);
				LODData.specularMap = CUtil::readString(pFP);
				LODData.opacityMap = CUtil::readString(pFP);
				LODData.giMap = giMap;

				LODData.m_pVertices = EE_NEW VertexComplex[faceCount * 3];
				LODData.m_pIndicies = EE_NEW unsigned short [faceCount * 3];

				fread(LODData.m_pVertices, VertexComplex::size, (faceCount * 3), pFP);
				for(unsigned int indice = 0; indice < (unsigned int)(3 * faceCount); indice++)
					LODData.m_pIndicies[indice] = indice;
				

				LODData.frameCount = 1;
				LODData.vertexCount = faceCount * 3;
				LODData.triangleCount = faceCount;

				D3DMesh *pMeshPart = new D3DMesh(this);
				pMeshPart->m_ElementSize = VertexComplex::size;
				if(FAILED(pMeshPart->Create(LODData)))
				{
					EE_LOGERROR("Failed to Create mesh part");
					EE_SAFEDELETE(pMeshPart);
				}

				pModelLOD->m_pMeshs[p] = pMeshPart;
			}

			lpModel->m_pLODs[L] = pModelLOD;
		}
	
		fread(&endCheck, sizeof(short), 1, pFP); 

		if(endCheck != EE_MODEL_CHECK)
			throw EE_EXCEPTION("The model file appears to be corrupt or read incorrectly."); 

		//Release this file
		fclose(pFP); 

		lpModel->CaclulateBoundSphere();
	
		m_Models.Add(lpModel); 
		*pOut = lpModel; 

		return S_OK; 
	}
	catch(CError::CErrorData errorData)
	{
		if(pFP)
			fclose(pFP); 

		EE_SAFEDELETE(lpModel); 
		CError::CError(errorData); 
		return E_FAIL; 
	}
}

/**************************************
 *Stores and returns a model according
 *to specified data
 **************************************/
HRESULT CD3D9Device::CreateModel(D3DModelLOD** pLODData, unsigned int LODcount, string& identifier, D3DModel **pOut)
{
	D3DModel *lpModel = NULL; 
	D3DModel *lppModel = NULL; 
	FILE *pFP			= NULL; 
	D3DModelLOD *pModel		= NULL; 
	short endCheck = -1; 
	short version;
	short GImap;
	short LODCount;
	string giMap;

	try
	{
		//Look for this model in the existing models list and if found
		//return it
		if(SUCCEEDED(SearchForResource(identifier, (IResource**) &lppModel, RESOURCE_MODEL)))
		{
			if(lppModel)
			{
				*pOut = lppModel; 
				return S_OK; 
			}
		}

		lpModel = new D3DModel(this);	
		lpModel->m_Identity = identifier; 
		lpModel->m_LODCount = LODcount;
		lpModel->m_pLODs = pLODData;

		lpModel->CaclulateBoundSphere();
		m_Models.Add(lpModel); 
		*pOut = lpModel; 

		return S_OK; 
	}
	catch(CError::CErrorData errorData)
	{
		EE_SAFEDELETE(lpModel); 
		CError::CError(errorData); 
		return E_FAIL; 
	}
}